package com.briup.smartcity_group1.service.impl;

import com.briup.smartcity_group1.bean.basic.BaseUser;
import com.briup.smartcity_group1.consts.TokenColumnNameConsts;
import com.briup.smartcity_group1.consts.UserRoleConsts;
import com.briup.smartcity_group1.consts.UserStatusConsts;
import com.briup.smartcity_group1.dao.basic.BaseUserMapper;
import com.briup.smartcity_group1.dao.ext.ArticleExtMapper;
import com.briup.smartcity_group1.dao.ext.BaseUserExtMapper;
import com.briup.smartcity_group1.exception.ServiceException;
import com.briup.smartcity_group1.service.IBaseUserService;
import com.briup.smartcity_group1.utils.JwtUtils;
import com.briup.smartcity_group1.utils.result.ResultCode;
import com.github.pagehelper.PageHelper;
import com.github.pagehelper.PageInfo;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;

import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;
import java.util.Map;
import java.util.Set;

/**用户管理模块服务实现
 * @author congee(congee02 @ 163.com)
 * @date 1/4/2023 8:28 PM
 */
@Service
@Slf4j
public class BaseUserServiceImpl implements IBaseUserService {

    @Resource(type = Set.class, name = "tokenBlackList")
    private Set<String> tokenBlackList;

    @Autowired
    private BaseUserExtMapper extMapper;

    @Autowired
    private BaseUserMapper mapper;

    @Autowired
    private ArticleExtMapper articleExtMapper;

    /**
     * 根据id删除用户信息
     * 当删除用户不存在时，删除失败，提示用户已经不存在
     * 当删除用户为管理员时删除失败，进行逻辑删除，将用户的状态设置为 禁用状态 status=1
     * 当删除用户时，如果用户已经发布了咨询信息，需要将对应的咨询信息删除
     *
     * @param id 用户id
     */
    @Override
    public void deleteById(int id) {
        BaseUser byId = mapper.selectByPrimaryKey(id);

        // 当删除用户不存在时，删除失败，提示用户已经不存在
        if (byId == null) {
            throw new ServiceException(ResultCode.USER_NOT_FOUND);
        }

        // 当删除用户为管理员时删除失败，提示管理员不能删除，或者可以进行逻辑删除，也是就是将用户的状态设置为 禁用状态 status=1
        if (UserRoleConsts.ROLE_ADMIN.equals(byId.getRole())) {
            byId.setStatus(UserStatusConsts.LOCKED);
            byId.setUserId(id);
            articleExtMapper.deleteByUserId(id);
            mapper.updateByPrimaryKey(byId);
        } else if (UserRoleConsts.ROLE_USER.equals(byId.getRole())) {
            // 当删除用户时，如果用户已经发布了咨询信息，需要将对应的咨询信息删除
            // RESTRICT DELETE
            articleExtMapper.deleteByUserId(id);
            mapper.deleteByPrimaryKey(id);
        }

    }

    /**
     * 通过token获取当前登录用户的信息
     * 使用 {@link JwtUtils#getInfo(String)} 获取 token 中的 username,
     * 再从数据库中根据 username 读取记录返回
     *
     * @param token 用户的token
     * @return 返回的用户信息
     * @throws ServiceException token 校验不通过 {@code ! JwtUtils.checkSign(token)} 或在黑名单 {@code tokenBlackList.contains(token)} 中
     */
    @Override
    public BaseUser currentUserInfo(String token) {

        // token 校验不通过 或者 在 黑名单 中
        if (! JwtUtils.checkSign(token) || tokenBlackList.contains(token)) {
            throw new ServiceException(ResultCode.USER_INVALID_TOKEN);
        }

        // 使用 {@link JwtUtils#getInfo(String)} 获取 token 中的 username,
        Map<String, Object> info = JwtUtils.getInfo(token);
        String name = info.get(TokenColumnNameConsts.USERNAME).toString();

        // 再从数据库中根据 username 读取记录返回
        BaseUser baseUser = extMapper.selectByName(name);

        if (baseUser == null) {
            throw new ServiceException(ResultCode.USER_NOT_FOUND);
        }

        return baseUser;
    }

    /**
     * 根据用户名角色、名字分页模糊查询用户信息
     * 查询用户名和用户角色信息为可选查询条件
     *
     * @param name     模糊查找的姓名
     * @param role     身份
     * @param pageNum  页码
     * @param pageSize 单页记录数量
     * @return 搜索结果的页面信息
     */
    @Override
    public PageInfo<BaseUser> findBaseUserLikeNameAndRoleByPage
                                (String name, Integer role, int pageNum, int pageSize) {
        log.info("尝试分页查询: name: {}, role: {}, pageNum: {}, pageSize: {}", name, role, pageNum, pageSize);
        return PageHelper.startPage(pageNum, pageSize, true)
                .doSelectPageInfo(() -> extMapper.findBaseUserLikeNameAndRole(name, role));
    }

    /**
     * 根据用户id更新用户信息
     * 允许管理员对所有用户信息进行更新操作, 如果用户是普通用户，只能更新自己的用户信息
     * 另外，需要考虑邮箱和手机号重复的问题
     * @param baseUser 更新用户信息
     */
    @Override
    public void updateById(BaseUser baseUser) {

        Integer userId = baseUser.getUserId();

        // 用于验证用户是否存在或者要更新的用户是不是当前登录用户
        BaseUser toValidate = mapper.selectByPrimaryKey(userId);

        if (toValidate == null) {
            throw new ServiceException(ResultCode.USER_NOT_FOUND);
        }

        String username = baseUser.getUsername();
        String email = baseUser.getEmail();
        String telephone = baseUser.getTelephone();

        // 考虑邮箱和手机号重复的问题
        if (extMapper.selectByName(username) != null) {
            throw new ServiceException(ResultCode.USER_REGISTER_DUPLICATE_USERNAME);
        }
        if (extMapper.selectByEmail(email) != null) {
            throw new ServiceException(ResultCode.USER_REGISTER_DUPLICATE_EMAIL);
        }
        if (extMapper.selectByPhone(telephone) != null) {
            throw new ServiceException(ResultCode.USER_REGISTER_DUPLICATE_TELEPHONE);
        }

        // 从 token 中获取当前用户身份
        HttpServletRequest request
                = ((ServletRequestAttributes) RequestContextHolder.getRequestAttributes()).getRequest();
        String token = request.getHeader("Authorization");

        Map<String, Object> info = JwtUtils.getInfo(token);
        Integer role = (Integer) info.get(TokenColumnNameConsts.ROLE);

        // 允许管理员对所有用户信息进行更新操作
        if (UserRoleConsts.ROLE_ADMIN.equals(role)) {
            mapper.updateByPrimaryKeySelective(baseUser);
            return;
        }

        // 如果用户是普通用户，只能更新自己的用户信息
        if (UserRoleConsts.ROLE_USER.equals(role)) {
            String usernameFromToken = info.get(TokenColumnNameConsts.USERNAME).toString();
            String usernameToValidate = toValidate.getUsername();
            if (usernameFromToken.equals(usernameToValidate)) {
                mapper.updateByPrimaryKeySelective(baseUser);
                return;
            }
            throw new ServiceException(ResultCode.USER_UPDATE_PERMISSION_DINED);
        }

    }

    /**更改用户头像
     * @param id      用户id
     * @param iconUrl 头像url
     */
    @Override
    public void changeIcon(Integer id, String iconUrl) {

        log.info("尝试更换头像: userId: {}, iconUrl: {}", id, iconUrl);

        BaseUser byPrimaryKey = mapper.selectByPrimaryKey(id);
        if (byPrimaryKey == null) {
            throw new ServiceException(ResultCode.USER_NOT_FOUND);
        }
        byPrimaryKey.setIcon(iconUrl);
        mapper.updateByPrimaryKeySelective(byPrimaryKey);
    }
}
